#include "BunnyAgent.h"
#include "AgentManager.h"
BunnyAgent::BunnyAgent()
{
}

BunnyAgent::~BunnyAgent()
{
}

void BunnyAgent::Initialize(std::vector<std::vector<Node*>> &pGrid)
{
	Agent::Initialize(pGrid);

	m_xSprite = m_xSpriteManager->LoadSprite("Images/Bunny.png", 5);
	m_xSprite->setOrigin(12.5f, 12.5f);
	m_iSenseRange = 3;
	m_fMoveSpeed = 3.5f;
	m_xAnimalType = Bunny;
	m_fHunger = 25;

	//Setting up the behavior tree. 
	//I create a sequncer and two action bide children. 
	//If the first child succeds, it goes to the second which then gets executed. Otherwise it fails and does nothing.
	SequencerBNode* wanderSeq= new SequencerBNode();
	BunnyAgentActionBnode* wander = new BunnyAgentActionBnode();
	BunnyAgentActionBnode* timeCheck = new BunnyAgentActionBnode();
	SequencerBNode* wolfSeq = new SequencerBNode();
	SelectorBNode* rootSel = new SelectorBNode();
	BunnyAgentActionBnode* lookWolf = new BunnyAgentActionBnode();
	BunnyAgentActionBnode* runWolf = new BunnyAgentActionBnode();
	
	SequencerBNode* foodSeq = new SequencerBNode();
	BunnyAgentActionBnode *lookFood = new BunnyAgentActionBnode();
	BunnyAgentActionBnode *goFood = new BunnyAgentActionBnode();
	BunnyAgentActionBnode *eatFood = new BunnyAgentActionBnode();

	lookFood->SetAgent(this);
	lookFood->FunctionPointer = &BunnyAgent::CheckForFood;
	goFood->SetAgent(this);
	goFood->FunctionPointer = &BunnyAgent::WalkTowardsFood;
	eatFood->SetAgent(this);
	eatFood->FunctionPointer = &BunnyAgent::EatFood;
	foodSeq->AddChildNode(lookFood);
	foodSeq->AddChildNode(goFood);
	foodSeq->AddChildNode(eatFood);

	lookWolf->SetAgent(this);
	lookWolf->FunctionPointer = &BunnyAgent::CheckForWolf;
	runWolf->SetAgent(this);
	runWolf->FunctionPointer = &BunnyAgent::RunFromWolf;
	wolfSeq->AddChildNode(lookWolf);
	wolfSeq->AddChildNode(runWolf);




	timeCheck->SetAgent(this);
	wander->SetAgent(this);
	timeCheck->FunctionPointer = &BunnyAgent::TimeCheck;
	wander->FunctionPointer = &BunnyAgent::Wander;
	wanderSeq->AddChildNode(timeCheck);
	wanderSeq->AddChildNode(wander);

	rootSel->AddChildNode(wolfSeq);
	rootSel->AddChildNode(foodSeq);
	rootSel->AddChildNode(wanderSeq);



	m_xNode = rootSel;

	
}

void BunnyAgent::Update(float pDeltaTime)
{
	/*if (m_fIdleTimer <= 0.0f && m_bFinishedPath)
	{*/
		SearchArea();
	//	m_fIdleTimer = 2.0f;
	//}
	if (m_fIdleTimer > 0.0f && m_bFinishedPath)
	{
		m_fIdleTimer -= pDeltaTime;
	}

	Agent::Update(pDeltaTime);
}

void BunnyAgent::Cleanup()
{
	Agent::Cleanup();
}

void BunnyAgent::SearchArea()
{
	// Find somewhere to go.
	// Look at all the nodes in the sense range and add anything interesting to a list
	SearchArea2();



	Think();
}

void BunnyAgent::Think()
{
	// Evaluate options
	// Look through the list of interesting things and find the best one for the agent to do
	
	m_xNode->Run();
	//Act();
}

void BunnyAgent::Act()
{
	// Interact with objects
	// If the target is not within range to interact with travel to the node and then interact

	// Find path to random node
	if (m_bFinishedPath)
	{
		sf::Vector2i curNodeID = m_xCurrentNode->m_vID;

		// Find a random node within the sense range and find a path too that node.
		bool foundTarget = false;
		while (!foundTarget)
		{
			int RandX = rand() % ((m_iSenseRange * 2) + 1) + (-m_iSenseRange);
			int RandY = rand() % ((m_iSenseRange * 2) + 1) + (-m_iSenseRange);

			if ((curNodeID.x + RandX <= 29) && (curNodeID.x + RandX >= 0) && (curNodeID.y + RandY <= 29) && (curNodeID.y + RandY >= 0))
			{
				if ((Grid[curNodeID.x + RandX][curNodeID.y + RandY]->m_bBlocked == false))
				{
					// Use A* to find a path to the node
					if (FindPath(Grid[curNodeID.x + RandX][curNodeID.y + RandY]))
					{
						// Travel to this node
						Travel();
						foundTarget = true;
					}
				}
			}
		}
	}
}



int BunnyAgent::Wander(BNode::Status p_Status)
{
	// Interact with objects
	// If the target is not within range to interact with travel to the node and then interact

	// Find path to random node
	if (m_bFinishedPath)
	{
		sf::Vector2i curNodeID = m_xCurrentNode->m_vID;

		// Find a random node within the sense range and find a path too that node.
		bool foundTarget = false;
		while (!foundTarget)
		{
			int RandX = rand() % ((m_iSenseRange * 2) + 1) + (-m_iSenseRange);
			int RandY = rand() % ((m_iSenseRange * 2) + 1) + (-m_iSenseRange);

			if ((curNodeID.x + RandX <= 29) && (curNodeID.x + RandX >= 0) && (curNodeID.y + RandY <= 29) && (curNodeID.y + RandY >= 0))
			{
				if ((Grid[curNodeID.x + RandX][curNodeID.y + RandY]->m_bBlocked == false) && (Grid[curNodeID.x + RandX][curNodeID.y + RandY] != m_xCurrentNode))
				{
					FindPath(Grid[curNodeID.x + RandX][curNodeID.y + RandY]);
					Travel();
					foundTarget = true;
					return BNode::Running;
				}
			}
		}
	
	}

}

int BunnyAgent::TimeCheck(BNode::Status p_Status)
{
		if (m_fIdleTimer <= 0.0f && m_bFinishedPath)
		{

			m_fIdleTimer = 2.0f;
			return BNode::Succeded;
		}
		return BNode::Failed;
}

int BunnyAgent::CheckForWolf(BNode::Status p_Status)
{
	for (int i = 0; i < m_CData.m_SearchDataList.size(); i++)
	{
		for (int y = 0; y < m_CData.m_SearchDataList[i]->m_Node->m_vAgents.size(); y++)
		{
			if (m_CData.m_SearchDataList[i]->m_Node->m_vAgents[y]->GetAnimalType() == Animals::Wolf)
			{
				m_CData.ClosestThreat = m_CData.m_SearchDataList[i]->m_Node;
				return BNode::Succeded;
			}
		}
	}
	return BNode::Failed;
}

int BunnyAgent::RunFromWolf(BNode::Status p_Status)
{

	if (p_Status != BNode::Running)
	{



		for (int i = 1; i < m_CData.m_SearchDataList.size(); i++)
		{
			m_CData.m_SearchDataList[i]->m_ManhattanDistance = aStar.CalculateMDistance(m_CData.ClosestThreat, m_CData.m_SearchDataList[i]->m_Node);
		}

		NodeSenseData* myTemporaryNode;   //Temporary integer to store (if necessary) the current element
		int end = 0;    //Run time condition

		while (end++ != m_CData.m_SearchDataList.size())// Will loop max. 10 times
		{
			bool swapped = false;
			for (int i = 0; i < m_CData.m_SearchDataList.size() - 1; i++)
			{

				if (m_CData.m_SearchDataList[i]->m_ManhattanDistance > m_CData.m_SearchDataList[i + 1]->m_ManhattanDistance) //If the current element 
				{
					myTemporaryNode = m_CData.m_SearchDataList[i];    //is bigger than the next

					m_CData.m_SearchDataList[i] = m_CData.m_SearchDataList[i + 1];//Change the positions
					m_CData.m_SearchDataList[i + 1] = myTemporaryNode;
					swapped = true;
				}
			}
			if (!swapped) break;
		}



		int randomVector = rand() & 10;

		randomVector = m_CData.m_SearchDataList.size() - randomVector -1;
		if (m_CData.m_SearchDataList[randomVector]->m_Node != m_xCurrentNode)
		{
			FindPath(m_CData.m_SearchDataList[randomVector]->m_Node);
			Travel();
			return BNode::Running;
		}
		else
		{
			return BNode::Failed;
		}

	}

	if (!m_bFinishedPath)
	{
	return BNode::Running;
	}
	else
	{
	return BNode::Succeded;
	}

}


int BunnyAgent::CheckForFood(BNode::Status p_Status)
{

	for (int i = 0; i < m_CData.m_SearchDataList.size(); i++)
	{
			if (m_CData.m_SearchDataList[i]->m_Node->m_xWorldObject != nullptr )
			{
				m_CData.ClosestFood = m_CData.m_SearchDataList[i]->m_Node;
			
				return BNode::Succeded;
			}
	}
	return BNode::Failed;
}
int BunnyAgent::WalkTowardsFood(BNode::Status p_Status)
{
	if (p_Status != BNode::Running)
	{
		std::vector<Node*> nodeVector;
		//Node* currentNode = nullptr;
		//int currentMD = 0;
		for (int i = 0; i < m_CData.m_SearchDataList.size(); i++)
		{
			if (m_CData.m_SearchDataList[i]->m_Node->m_xWorldObject != nullptr)
			{
				nodeVector.push_back(m_CData.m_SearchDataList[i]->m_Node);
			}
		}
		int randomVector = rand() & nodeVector.size() -1;
		
		if (nodeVector[randomVector] != m_xCurrentNode)
		{
			FindPath(nodeVector[randomVector]);
			
			Travel();
			return BNode::Running;
		}

		if (m_CData.ClosestFood != m_xCurrentNode)
		{
			FindPath(m_CData.ClosestFood);
			Travel();
			return BNode::Running;
		}
		else
		{
			return BNode::Failed;
		}
		}

	if (!m_bFinishedPath)
	{
		return BNode::Running;
	}
	else
	{
	
		return BNode::Succeded;
	}

}
int BunnyAgent::EatFood(BNode::Status p_Status)
{
	if (m_CData.ClosestFood->m_xWorldObject != nullptr)
	{
		if (m_CData.ClosestFood == m_xCurrentNode)
		{
			//m_CData.ClosestFood->m_xWorldObject->StartDeletion();
			m_fHunger += 50;
			std::cout << "Bunny Eat" << "\n";
			WorldObjectManager::GetInstance()->DeleteObject(m_CData.ClosestFood->m_xWorldObject);
			m_CData.ClosestFood->m_xWorldObject = nullptr;
			if (m_fHunger > 50)
			{
			AgentManager::GetInstance()->SpawnAnimal(Animals::Bunny, m_xCurrentNode);
			m_fHunger -= 5;
			}
			
		
			return BNode::Succeded;



		}
		
	}
	//std::cout << "No food here Q_Q" << "\n";

	return BNode::Failed;
}